/** RMI Step 2: Write a server application
   The server application
	- extends java.server.RemoteObject or a subclass of RemoteObject. The commonly
	  used RemoteObject's subclasses are: Acativatable and UnicastRemoteObject. The
	  Activatable allows system to activate remote objects. UnicastRemoteObject defines
	  a non-replicated object that is running only when client process is alive.
	- implments the ChevalDBServer interface;
	- provides services and returns data/messages through methods defined in
	  remote interface.
   	- has a main() function that define a remote object and bind the object to a name.

   Compile the server application:	javac 	ChevalDBServer.java
   Generate sub class:			rmic 	ChevalDBServer
   Run the rmiregistry server utility
     that allow system to manage the
     remote object			rmiregistry &
   Run the remote application that
     define a remote object and bind a
     unique name to the remote
     object				java ChevalDBServerImpl &

Notice that the schema used in this program doesn't work if more than one user try
to access the database concurrently.
*/
import java.rmi.*;
import java.rmi.server.*;
import java.util.*;
import java.io.*;
import java.net.*;
import java.sql.*;

public class ChevalDBServerImpl extends UnicastRemoteObject implements ChevalDBServer {
   Vector			rows = null ;
   String			heading;
   private Connection		cnn;
   private Statement		stmt = null;
   String url = "jdbc:oracle:thin:@cheval:1521:TEST";
   String usr = "CS440" ;
   String pwd = "student1" ;
   int    hitCount = 1;

   public ChevalDBServerImpl() throws RemoteException
   {
      super();
      connectToDatabase();
   }

   
   private void connectToDatabase() {

        System.err.println( "Connecting to database..." );

	try { DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
	} catch(SQLException e) {
			System.err.print("ClassNotFoundException: ");
			System.err.println(e.getMessage());}
	try {
		cnn = DriverManager.getConnection(url, usr, pwd) ;
		stmt = cnn.createStatement() ;
		System.err.println("Connected to database!");
	} catch( SQLException e ) { System.err.println(e.toString()) ; }
          catch( Exception e ) { e.printStackTrace(); }
   }

   public void finalize() { 
	try { stmt.close(); cnn.close(); }
	catch (SQLException e) { System.err.println(e.toString()); }
   }

   public Vector getResultSet(String sql)  throws RemoteException
   {	try {
		String SQL = null;
		if ( sql != null ) SQL = sql.toUpperCase();

		{ int k = sql.lastIndexOf(";");
		  if ( k > 0 ) sql = sql.substring(0, k);
		}

		if (SQL.lastIndexOf("DELETE")>=0 ) sql = null;
		if (SQL.lastIndexOf("UPDATE")>=0 ) sql = null;
		if (SQL.lastIndexOf("SELECT")< 0 ) sql = null;

		if ( sql == null ) sql = "SELECT * FROM AddressBook";

		if ( rows != null ) rows.clear();
		rows = new Vector(30, 10);
		ResultSet rs = stmt.executeQuery(sql) ;
		ResultSetMetaData mdata = rs.getMetaData();
		int colCnt = mdata.getColumnCount();
		DBRow lenRow = new DBRow(colCnt), row = new DBRow(colCnt);
		
		// get column heading and their display lengths.
		for ( int i = 1; i <= colCnt; i ++ ) {
			int len = mdata.getColumnDisplaySize(i);
			switch( mdata.getColumnType(i) ) {
		   		case Types.NUMERIC: len = 10; break;
		   		case Types.DECIMAL: len = 10; break;
		   		case Types.DATE:    len = 10; break;
		   		case Types.TIME:    len = 10; break;
		   		case Types.TIMESTAMP: len = 10; break;
			}
			lenRow.setCol(i-1, len + "");
			row.setCol(i-1, mdata.getColumnName(i));
		}
		rows.addElement(lenRow); rows.addElement(row);

		// Get rows and coumns.
		int k = 2;
		String s ;
		while ( rs.next() ) {
		    row = new DBRow(colCnt);
		    for (int i = 1; i <= colCnt; i ++) {
			s = rs.getString(i);
			if ( s == null ) row.setCol(i-1, "");
			else if ( s.length() > Integer.parseInt(lenRow.getCol(i-1)) )
		    		row.setCol(i-1, s.substring(0,
					Integer.parseInt(lenRow.getCol(i-1))));
			     else
		    		row.setCol(i-1, rs.getString(i) + "");
		    }
		    rows.addElement(row);
		    k++;
		}
		rs.close(); rows.trimToSize();
		System.out.println(Calendar.getInstance().getTime().toString() +
					" Request No: " + hitCount++);
		return rows;
	} catch ( SQLException e ) {
	     System.err.println ("Error in getResultSet(): " +e.toString());
	     System.err.println("SQL Statement: " + sql); }
	  return rows;
   }

   public static void main( String args[] ) throws Exception
   {     
      System.err.println(
         "Initializing DB server: please wait." );

      // create server object
      ChevalDBServerImpl temp = new ChevalDBServerImpl();

      // bind ChevalDBServerImpl object to the rmiregistry
      String serverObjectName = "//localhost/ChevalDBServer";
      Naming.rebind( serverObjectName, temp );
      System.err.println( "The "+ serverObjectName + " is up and running." );
   }
}

